#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <list>
#include <mutex>
#include <queue>
#include <thread>
#if 0
// 如何创建一个线程
// std::thread
// 定义一个线程对象，接收一个函数，或lambda表达式，及其参数，子线程自动开始执行
//
// 主线程结束，不能存在子线程仍然在执行,使用t.join() 或者t.detach()
// t.join()  等待t线程结束之后继续运行
// t.detach() 设置t为分离线程，主线程结束，整个进程结束，所有子线程自动结束
//
void threadWork() {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "hello thread" << std::endl;
}

int main() {
    std::thread t(threadWork);
    t.join();
    /* t.detach(); */

    std::cout << "main thread done!" << std::endl;
    return 0;
}
#endif

#if 0
// std::mutex 以及 std::lock_guard 的使用
// c++ thread 模拟车站三个窗口卖票的程序
int count = 100;  // 一共100张车票， 由三个窗口一起卖票
std::mutex mutex;
// 模拟卖票的线程函数
void sell(int idx) {
    while (count > 0) {  // count = 1 锁+双重判断
        mutex.lock();    // 临界区
        if (count > 0) {
            std::cout << "窗口:" << idx << " 卖票:" << count << std::endl;
            count--;
        }
        mutex.unlock();
        std::this_thread::sleep_for(std::chrono::milliseconds(2));
    }
}

void sell2(int idx) {
    while (count > 0) {
        {
            // 构造自动lock(),析构自动unlock(),防止代码中抛出异常或提前返回没有执行到手动的unlock()函数
            // 基于RAII的工作原理，栈上的对象一定会自动析构，所以可以保证锁的自动释放且一定会释放
            // 类似于scoped_ptr
            std::lock_guard<std::mutex> lock(mutex);
            if (count > 0) {
                std::cout << "窗口:" << idx << " 卖票:" << count << std::endl;
                count--;
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(2));
    }
}
int main() {
    std::list<std::thread> threads;
    for (int i = 1; i <= 3; i++) {
        threads.push_back(std::thread(sell2, i));
    }
    for (auto& t : threads) {
        t.join();
    }
    return 0;
}
#endif

#if 0
// 基于std::mutex std::unique_lock std::condition_variable 实现生产者消费者模型
std::mutex mutex;
std::condition_variable cv;

class Queue {
public:
    void put(int val) {
        std::unique_lock<std::mutex> lock(mutex);
        while (!queue.empty()) {
            cv.wait(lock);  // 线程进入等待状态， 调用lock.unlock()释放锁
        }
        queue.push(val);
        std::cout << "生产" << val << std::endl;
        cv.notify_all();
    }

    int get() {
        std::unique_lock<std::mutex> lock(mutex);
        while (queue.empty()) {
            cv.wait(lock);
        }
        int val = queue.front();
        queue.pop();
        std::cout << "消费" << val << std::endl;
        cv.notify_all();
        return val;
    }

private:
    std::queue<int> queue;
};

void produce(Queue* queue) {
    for (int i = 1; i <= 10; ++i) {
        queue->put(i);
        std::this_thread::sleep_for(std::chrono::milliseconds(2));
    }
}

void consum(Queue* queue) {
    for (int i = 1; i <= 10; ++i) {
        queue->get();
        std::this_thread::sleep_for(std::chrono::milliseconds(2));
    }
}
int main() {
    Queue q;
    std::thread t1(produce, &q);
    std::thread t2(consum, &q);

    t1.join();
    t2.join();
    return 0;
}
#endif
